package apps.sim.http;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import java.security.AccessController;
import java.util.HashMap;
import java.util.Map;

import sun.security.action.GetPropertyAction;
import apps.sim.core.log.Console;
import apps.sim.core.log.Console.Color;
import apps.sim.util.InvalidSessionException;

import com.sun.net.httpserver.Headers;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;

public abstract class HttpBaseHandler implements HttpHandler {
	private static final int HTTP_SUCCESS = 200;
	private static final int HTTP_INTERNAL_ERROR = 500;
	private static final int HTTP_UNAUTHORIZED = 401;
	public static final Map<Class<?>, Class<?>> PRIMITIVES_TO_WRAPPERS = new HashMap<Class<?>, Class<?>>();
	public static final Map<Class<?>, Class<?>> WRAPPERS_TO_PRIMITIVES = new HashMap<Class<?>, Class<?>>();
	static {
		PRIMITIVES_TO_WRAPPERS.put(boolean.class, Boolean.class);
		PRIMITIVES_TO_WRAPPERS.put(byte.class, Byte.class);
		PRIMITIVES_TO_WRAPPERS.put(char.class, Character.class);
		PRIMITIVES_TO_WRAPPERS.put(double.class, Double.class);
		PRIMITIVES_TO_WRAPPERS.put(float.class, Float.class);
		PRIMITIVES_TO_WRAPPERS.put(int.class, Integer.class);
		PRIMITIVES_TO_WRAPPERS.put(long.class, Long.class);
		PRIMITIVES_TO_WRAPPERS.put(short.class, Short.class);
		PRIMITIVES_TO_WRAPPERS.put(void.class, Void.class);

		WRAPPERS_TO_PRIMITIVES.put(Boolean.class, boolean.class);
		WRAPPERS_TO_PRIMITIVES.put(Byte.class, byte.class);
		WRAPPERS_TO_PRIMITIVES.put(Character.class, char.class);
		WRAPPERS_TO_PRIMITIVES.put(Double.class, double.class);
		WRAPPERS_TO_PRIMITIVES.put(Float.class, float.class);
		WRAPPERS_TO_PRIMITIVES.put(Integer.class, int.class);
		WRAPPERS_TO_PRIMITIVES.put(Long.class, long.class);
		WRAPPERS_TO_PRIMITIVES.put(Short.class, short.class);
		WRAPPERS_TO_PRIMITIVES.put(Void.class, void.class);

	}

	public final void handle(HttpExchange exchange) throws IOException {
		try {
			execute(exchange);
		} catch (InvalidSessionException e) {
			errorResponse(exchange, e, HTTP_UNAUTHORIZED);
		} catch (Throwable e) {
			Console.print(e.getMessage(), Color.ERROR);
			e.printStackTrace();
			errorResponse(exchange, e);
		}
	}

	protected abstract void execute(HttpExchange exchange) throws Exception;

	protected Map<String, String> extractParams(URI uri) {
		final Map<String, String> map = new HashMap<String, String>();
		if (uri.getQuery() != null) {
			final String[] split = uri.getQuery().split("&");
			for (String string : split) {
				// string = string.replaceAll("\\?", "");
				final int indexOf = string.indexOf("=");
				if (indexOf != -1) {
					map.put(string.substring(0, indexOf), string.substring(indexOf + 1));
				} else {
					map.put(string, "");
				}
			}
		}
		return map;
	}

	protected void write(OutputStream out, InputStream in) throws IOException {
		int i;
		while ((i = in.read()) != -1) {
			out.write(i);
		}
	}

	protected void errorResponse(HttpExchange exchange, Throwable e) throws IOException {
		errorResponse(exchange, e, HTTP_INTERNAL_ERROR);
	}

	protected void errorResponse(HttpExchange exchange, Throwable e, int code) throws IOException {
		final Map<String, String> params = extractParams(exchange.getRequestURI());
		final String row = params.get("rowid");
		final Headers responseHeaders = exchange.getResponseHeaders();
		responseHeaders.set("Content-Type", "text/html;charset=utf-8");
		exchange.sendResponseHeaders(code, 0);
		final OutputStream responseBody = exchange.getResponseBody();
		final String message = (row != null ? row + "_ROW_NUM_" : "") + e.getClass().getSimpleName() + ":" + (e.getMessage() != null ? e.getMessage() : "Unknown error occured");
		final byte[] encode = encode(message, "UTF-8");
		responseBody.write(encode);
		responseBody.close();
	}

	protected void successResponse(HttpExchange exchange, InputStream bytes, String contentType) throws IOException {
		Headers responseHeaders = exchange.getResponseHeaders();
		responseHeaders.set("Content-Type", contentType != null ? contentType : "text/html;charset=utf-8");
		exchange.sendResponseHeaders(HTTP_SUCCESS, 0);
		OutputStream responseBody = exchange.getResponseBody();
		write(responseBody, bytes);
		responseBody.close();
	}

	protected void successResponse(HttpExchange exchange, InputStream bytes) throws IOException {
		successResponse(exchange, bytes, "text/html;charset=utf-8");
	}

	protected void successResponse(HttpExchange exchange, String bytes) throws IOException {
		successResponse(exchange, new ByteArrayInputStream((bytes != null ? bytes : "null").getBytes()), "text/html;charset=utf-8");
	}

	private byte[] encode(String message, String string) {
		return message.replaceAll("<", "&lt;").replaceAll(">", "&gt;").getBytes();
	}

	public static void createSettingsFolder() {
		final String doPrivileged = AccessController.doPrivileged(new GetPropertyAction("user.home"));
		final File file = new File(doPrivileged + "/.shycop");
		if (!file.exists()) {
			file.mkdir();
		}
	}

	protected File getShycopConfig() {
		final String doPrivileged = AccessController.doPrivileged(new GetPropertyAction("user.home"));
		final File file = new File(doPrivileged + "/.shycop/.shycop.config");
		return file;
	}

	protected static File getSettingFile() {
		final String doPrivileged = AccessController.doPrivileged(new GetPropertyAction("user.home"));
		final File file = new File(doPrivileged + "/.shycop/.shycop.proxy.config");
		return file;
	}
}
